#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/11/22 10:19
# @Author  : FuKai ZHANG
# @File    : Basepage.py
# @Description :结合显示等待，封装元素定位、元素操作，文件上传等方法

from selenium.webdriver.common.by import By
from utils.Logging_tools.log_control import INFO, ERROR
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.wait import WebDriverWait as WD
from selenium.webdriver.support import expected_conditions as ec
from selenium.common.exceptions import (
    TimeoutException,
    NoAlertPresentException,
    InvalidSwitchToTargetException,
)
import pywinauto
from pywinauto.keyboard import send_keys
from common.setting import ensure_path_sep


class BasePage(object):
    def __init__(self, driver, timeout=10):
        self.ELEMENT_LOCATOR_MAP = {"xpath": By.XPATH,
                                    "id": By.ID,
                                    "name": By.NAME,
                                    "css": By.CSS_SELECTOR,
                                    "class": By.CLASS_NAME}
        self.driver = driver
        self.out_time = timeout

    # 元素定位
    def find_element(self, by, locator, model):  # 这里model可以理解为元素的名字，方便在日志中打印
        try:
            element = WebDriverWait(self.driver, self.out_time).until(
                lambda x: x.find_element(self.ELEMENT_LOCATOR_MAP[by.lower()], locator))
        except TimeoutException as t:
            ERROR.logger.error(f'查找"{model}"元素失败,定位方式:{locator}')
            print('error: found "{}" timeout!'.format(locator), t)
        else:
            return element

    # 元素集定位
    def find_elements(self, by, locator, model=None):
        INFO.logger.info(f'查找"{model}"元素集，元素定位:{locator}')
        try:
            elements = WD(self.driver, self.out_time).until(lambda x: x.find_elements(by, locator))
        except TimeoutException:
            ERROR.logger.error(f'查找"{model}"元素集失败,定位方式:{locator}')
        else:
            return elements

    # 判断元素是否存在
    def is_element_exist(self, by, locator, model=None):
        INFO.logger.info(f'断言"{model}"元素存在，元素定位:{locator}')
        if by.lower() in self.ELEMENT_LOCATOR_MAP:
            try:
                WD(self.driver, self.out_time). \
                    until(ec.visibility_of_element_located((self.ELEMENT_LOCATOR_MAP[by], locator)))
            except TimeoutException:
                ERROR.logger.error(f'断言"{model}"元素不存在,定位方式:{locator}')
                # 截图
                return False
            return True
        else:
            print('the "{}" error!'.format(by))

    # 等待alert出现然后切换
    def switch_to_alert(self):
        """
        assert alert if exsit
        :return: alert obj
        """
        try:
            re = WD(self.driver, self.out_time).until(ec.alert_is_present())
        except (TimeoutException, NoAlertPresentException):
            print("error:no found alert")
        else:
            return self.driver.switch_to.alert

    # 获取alert 的提示信息
    def get_alert_text(self, model=None):
        """获取alert的提示信息"""
        INFO.logger.info(f"获取{model}的弹窗提示信息")
        alert = self.switch_to_alert()
        if alert:
            return alert.text
        else:
            return None

    # 弹窗确认
    def alert_accept(self):
        """
        alert 确认
        :return:
        """
        INFO.logger.info('点击弹窗确认按钮成功')
        self.switch_to_alert().accept()

    # 切换iframe
    def switch_to_frame(self, by, locator, model):
        """判断frame是否存在，存在就跳到iframe,有显示等待"""

        if by.lower() in self.ELEMENT_LOCATOR_MAP:
            try:
                WD(self.driver, self.out_time). \
                    until(ec.frame_to_be_available_and_switch_to_it((self.ELEMENT_LOCATOR_MAP[by], locator)))
                # time.sleep(0.5)
                INFO.logger.info(f'{model}iframe切换成功')
            except TimeoutException:
                ERROR.logger.error(f'{model}iframe 切换失败!!!')
                # 截图

        else:
            print('the "{}" error!'.format(by))

    def switch_to_default_frame(self):
        """返回默认的frame"""
        INFO.logger.info('切换到默认页面')
        try:
            self.driver.switch_to.default_content()
            INFO.logger.info('返回默认frame成功')
        except InvalidSwitchToTargetException:
            ERROR.logger.error('返回默认窗口失败!!!')

    # 获取某一个元素的text信息
    def get_element_text(self, by, locator, model, name=None):
        """获取某一个元素的text信息"""
        INFO.logger.info(f'开始获取"{model}"元素文本内容，元素定位:{locator}')
        try:
            element = self.find_element(by, locator, model)
            if name:
                return element.get_attribute(name)
            else:
                INFO.logger.info(f'成功获取"{model}"元素的文本内容"{element.text}",元素定位:{locator}')
                return element.text
        except AttributeError:
            ERROR.logger.error(f'获取"{model}"元素文本内容失败,元素定位:{locator}')
            # 截图

    # 获取多个元素的text信息
    def get_elements_text(self, by, locator, model):
        """获取多个元素的text信息"""
        try:
            element = self.find_elements(by, locator)
            text_list = []
            for i in element:
                text = i.text
                text_list.append(text)
            return text_list
        except AttributeError:
            ERROR.logger.error(f'获取多个"{model}"元素文本内容失败,元素定位:{locator}')
            return None

    # 加载url
    def load_url(self, url):
        """打开url"""
        self.driver.get(url)

    # 获取页面源码
    def get_source(self):
        """获取页面源码"""
        return self.driver.page_source

    # 获取页面的标题
    def get_title(self):
        """获取页面的标题"""
        return self.driver.title

    # send_keys操作
    def send_keys(self, by, locator, model, value):
        """写数据"""
        INFO.logger.info(f'在"{model}"输入"{value}",元素定位:{locator}')
        try:
            element = self.find_element(by, locator, model)
            element.send_keys(value)
        except AttributeError:
            ERROR.logger.error(f'"{model}"输入操作失败!')

    # 等待元素可点击
    def wait_element_clickable(self, by, locator, model):
        if by.lower() in self.ELEMENT_LOCATOR_MAP:
            try:
                element = WD(self.driver, self.out_time). \
                    until(ec.element_to_be_clickable((self.ELEMENT_LOCATOR_MAP[by], locator)))
            except TimeoutException:
                ERROR.logger.error(f'"{model}不可以点击')
                # 截图
            else:
                INFO.logger.info(f'"{model}"可以点击')
                return element
        else:
            print('the "{}" error!'.format(by))

    # 点击某个元素
    def click(self, by, locator, model):
        """显示等待某个元素可点击，然后点击元素"""
        element = self.wait_element_clickable(by, locator, model)

        if element:
            element.click()
            INFO.logger.info(f'点击"{model}",元素定位:{locator}')
        else:
            ERROR.logger.error(f'"{model}"点击失败')

    # 等待元素可见
    def wait_element_to_be_located(self, by, locator, model):
        """显示等待某个元素出现，且可见"""
        INFO.logger.info(f'等待"{model}"元素,定位方式:{locator}')
        try:
            return WD(self.driver, self.out_time).until(
                ec.presence_of_element_located((self.ELEMENT_LOCATOR_MAP[by], locator)))
        except TimeoutException:
            ERROR.logger.error(f'等待"{model}"元素失败,定位方式:{locator}')

    # 文件上传
    @staticmethod
    def upload_file(file_name):
        """上传文件"""
        # 使用pywinauto来选择文件
        app = pywinauto.Desktop()
        # 选择文件上传的窗口，这里默认使用谷歌浏览器，打开的窗口名默认为“打开”
        dlg = app["打开"]

        # 选择文件地址输入框，点击激活
        dlg["Toolbar3"].click()
        # 键盘输入上传文件的路径>>>记住不是文件的地址啊，是文件的上一层地址.
        send_keys(ensure_path_sep("\\files"))  # 需要上传的文件默认地址
        # 键盘输入回车，打开该路径
        send_keys("{VK_RETURN}")
        # 在文件名输入框输入文件名
        dlg["文件名(&N):Edit"].type_keys(file_name)
        # 如我实战的：
        # dlg["文件名(&N):Edit"].type_keys("接口测试文件.pdf")
        # 点击打开
        dlg["打开(&O)"].click()
